{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Explore urban networks and amenities as interactive web maps\n",
    "\n",
    "Author: [Geoff Boeing](https://geoffboeing.com/)\n",
    "\n",
    "Use OSMnx to download a street network, calculate a route between two points, and create a Leaflet web map using GeoPandas [explore](https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoDataFrame.explore.html). See the GeoPandas documentation for more style details.\n",
    "\n",
    "  - [Documentation](https://osmnx.readthedocs.io/)\n",
    "  - [Journal article and citation info](https://doi.org/10.1111/gean.70009)\n",
    "  - [Code repository](https://github.com/gboeing/osmnx)\n",
    "  - [Examples gallery](https://github.com/gboeing/osmnx-examples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#!uv pip install --system --quiet osmnx[all] folium mapclassify\n",
    "import networkx as nx\n",
    "import osmnx as ox\n",
    "\n",
    "ox.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# download a street network then solve a shortest-path route on it\n",
    "weight = \"length\"\n",
    "G = ox.graph.graph_from_place(\"Piedmont, CA, USA\", network_type=\"drive\")\n",
    "orig = next(iter(G.nodes))\n",
    "dest = list(G.nodes)[-1]\n",
    "route = ox.routing.shortest_path(G, orig, dest, weight=weight)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Explore a city's street network as an interactive web map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# explore graph edges interactively, with a simple one-liner\n",
    "ox.convert.graph_to_gdfs(G, nodes=False).explore()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can zoom into the street network above or hover over any edge to get more info."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# explore graph nodes interactively, with different basemap tiles\n",
    "nodes = ox.convert.graph_to_gdfs(G, edges=False)\n",
    "nodes.explore(tiles=\"cartodbpositron\", marker_kwds={\"radius\": 8})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# explore nodes and edges together in a single map\n",
    "nodes, edges = ox.convert.graph_to_gdfs(G)\n",
    "m = edges.explore(color=\"skyblue\", tiles=\"cartodbdarkmatter\")\n",
    "nodes.explore(m=m, color=\"pink\", marker_kwds={\"radius\": 6})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Explore attributes of the nodes and edges visually"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# explore graph edges interactively, colored by length\n",
    "edges.explore(tiles=\"cartodbdarkmatter\", column=\"length\", cmap=\"plasma\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# explore graph nodes interactively, colored by betweenness centrality\n",
    "nx.set_node_attributes(G, nx.betweenness_centrality(G, weight=\"length\"), name=\"bc\")\n",
    "nodes = ox.convert.graph_to_gdfs(G, edges=False)\n",
    "nodes.explore(tiles=\"cartodbdarkmatter\", column=\"bc\", marker_kwds={\"radius\": 8})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Explore routes as an interactive web map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# explore a route interactively\n",
    "route_edges = ox.routing.route_to_gdf(G, route, weight=weight)\n",
    "route_edges.explore(tiles=\"cartodbpositron\", style_kwds={\"weight\": 5})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# explore graph edges and route together in a single map\n",
    "m = edges.explore(color=\"maroon\", tiles=\"cartodbdarkmatter\")\n",
    "m = route_edges.explore(m=m, color=\"yellow\", style_kwds={\"weight\": 5})\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# or explore multiple routes together in a single map\n",
    "routes = ox.routing.k_shortest_paths(G, orig, dest, k=200, weight=weight)\n",
    "gdfs = (ox.routing.route_to_gdf(G, route, weight=weight) for route in routes)\n",
    "m = edges.explore(color=\"#222222\", tiles=\"cartodbdarkmatter\")\n",
    "for route_edges in gdfs:\n",
    "    m = route_edges.explore(m=m, color=\"cyan\", style_kwds={\"weight\": 5, \"opacity\": 0.05})\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Explore building footprints, transit lines/stops, or amenities"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# define some options\n",
    "place = \"Pasadena, CA, USA\"\n",
    "tiles = \"cartodbdarkmatter\"\n",
    "mk = {\"radius\": 6}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# explore a city's bus stops and rail transit interactively\n",
    "bus = ox.features.features_from_place(place, tags={\"highway\": \"bus_stop\"})\n",
    "m = bus.explore(tiles=tiles, color=\"red\", tooltip=\"name\", marker_kwds=mk)\n",
    "rail = ox.features.features_from_place(place, tags={\"railway\": \"light_rail\"})\n",
    "m = rail.explore(m=m, tiles=tiles, color=\"yellow\", tooltip=\"name\")\n",
    "stations = ox.features.features_from_place(place, tags={\"railway\": \"station\"})\n",
    "stations.explore(m=m, tiles=tiles, color=\"yellow\", tooltip=\"name\", marker_kwds=mk)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# explore a city's parks interactively\n",
    "parks = ox.features.features_from_place(place, tags={\"leisure\": \"park\"})\n",
    "parks.explore(tiles=tiles, color=\"lime\", tooltip=\"name\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# explore a neighborhood's buildings interactively\n",
    "gdf = ox.features.features_from_place(\n",
    "    \"Chinatown, San Francisco, California\",\n",
    "    tags={\"building\": True},\n",
    ")\n",
    "cols = [\"height\", \"addr:housenumber\", \"addr:street\", \"addr:postcode\"]\n",
    "gdf.explore(tiles=\"cartodbdarkmatter\", tooltip=cols)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# explore a neighborhood's buildings + street network interactively\n",
    "place = \"Chinatown, San Francisco, California\"\n",
    "cols = [\"height\", \"addr:housenumber\", \"addr:street\", \"addr:postcode\"]\n",
    "G = ox.graph.graph_from_place(place, network_type=\"drive\", truncate_by_edge=True)\n",
    "gdf = ox.features.features_from_place(place, tags={\"building\": True})\n",
    "m = gdf.explore(tiles=tiles, tooltip=cols)\n",
    "ox.convert.graph_to_gdfs(G, nodes=False).explore(m=m, color=\"yellow\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# you can save a web map as an HTML file for reuse elsewhere\n",
    "m.save(\"data/graph.html\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
